package com.cpems.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cpems.common.utils.DateUtils;
import com.cpems.system.domain.ElectricityU;
import com.cpems.system.domain.ElectricityI;
import com.cpems.system.domain.ElectricityP;
import com.cpems.system.domain.ElectricityW;
import com.cpems.system.domain.EnergyStatistics;
import com.cpems.system.domain.vo.ElectricityUVo;
import com.cpems.system.domain.vo.ElectricityIVo;
import com.cpems.system.domain.vo.ElectricityPVo;
import com.cpems.system.domain.vo.ElectricityWVo;
import com.cpems.system.domain.vo.EnergyStatisticsVo;
import com.cpems.system.mapper.ElectricityUMapper;
import com.cpems.system.mapper.ElectricityIMapper;
import com.cpems.system.mapper.ElectricityPMapper;
import com.cpems.system.mapper.ElectricityWMapper;
import com.cpems.system.mapper.EnergyStatisticsMapper;
import com.cpems.system.service.IDataQueryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 数据查询服务实现类
 * 用于替代MQTT和RabbitMQ，直接从数据库查询电力数据
 * 
 * @author cpems
 * @date 2025-01-10
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class DataQueryServiceImpl implements IDataQueryService {

    private final ElectricityUMapper electricityUMapper;
    private final ElectricityIMapper electricityIMapper;
    private final ElectricityPMapper electricityPMapper;
    private final ElectricityWMapper electricityWMapper;
    private final EnergyStatisticsMapper energyStatisticsMapper;

    /**
     * 根据设备ID查询最新电压值
     */
    @Override
    public ElectricityUVo getLatestVoltageByClientId(String clientId) {
        log.debug("查询设备{}的最新电压值", clientId);
        
        LambdaQueryWrapper<ElectricityU> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ElectricityU::getClientId, clientId)
               .orderByDesc(ElectricityU::getCreateTime)
               .last("LIMIT 1");
        
        return electricityUMapper.selectVoOne(wrapper);
    }

    /**
     * 根据设备ID和时间范围查询电压值列表
     */
    @Override
    public List<ElectricityUVo> getVoltageByClientIdAndTimeRange(String clientId, Date startTime, Date endTime) {
        log.debug("查询设备{}在时间范围[{}, {}]内的电压值", clientId, startTime, endTime);
        
        LambdaQueryWrapper<ElectricityU> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ElectricityU::getClientId, clientId)
               .ge(startTime != null, ElectricityU::getCreateTime, startTime)
               .le(endTime != null, ElectricityU::getCreateTime, endTime)
               .orderByDesc(ElectricityU::getCreateTime);
        
        return electricityUMapper.selectVoList(wrapper);
    }

    /**
     * 根据设备ID查询最新电流值
     */
    @Override
    public ElectricityIVo getLatestCurrentByClientId(String clientId) {
        log.debug("查询设备{}的最新电流值", clientId);
        
        LambdaQueryWrapper<ElectricityI> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ElectricityI::getClientId, clientId)
               .orderByDesc(ElectricityI::getCreateTime)
               .last("LIMIT 1");
        
        return electricityIMapper.selectVoOne(wrapper);
    }

    /**
     * 根据设备ID和时间范围查询电流值列表
     */
    @Override
    public List<ElectricityIVo> getCurrentByClientIdAndTimeRange(String clientId, Date startTime, Date endTime) {
        log.debug("查询设备{}在时间范围[{}, {}]内的电流值", clientId, startTime, endTime);
        
        LambdaQueryWrapper<ElectricityI> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ElectricityI::getClientId, clientId)
               .ge(startTime != null, ElectricityI::getCreateTime, startTime)
               .le(endTime != null, ElectricityI::getCreateTime, endTime)
               .orderByDesc(ElectricityI::getCreateTime);
        
        return electricityIMapper.selectVoList(wrapper);
    }

    /**
     * 根据设备ID查询最新功率值
     */
    @Override
    public ElectricityPVo getLatestPowerByClientId(String clientId) {
        log.debug("查询设备{}的最新功率值", clientId);
        
        LambdaQueryWrapper<ElectricityP> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ElectricityP::getClientId, clientId)
               .orderByDesc(ElectricityP::getCreateTime)
               .last("LIMIT 1");
        
        return electricityPMapper.selectVoOne(wrapper);
    }

    /**
     * 根据设备ID和时间范围查询功率值列表
     */
    @Override
    public List<ElectricityPVo> getPowerByClientIdAndTimeRange(String clientId, Date startTime, Date endTime) {
        log.debug("查询设备{}在时间范围[{}, {}]内的功率值", clientId, startTime, endTime);
        
        LambdaQueryWrapper<ElectricityP> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ElectricityP::getClientId, clientId)
               .ge(startTime != null, ElectricityP::getCreateTime, startTime)
               .le(endTime != null, ElectricityP::getCreateTime, endTime)
               .orderByDesc(ElectricityP::getCreateTime);
        
        return electricityPMapper.selectVoList(wrapper);
    }

    /**
     * 根据设备ID查询最新用电量值
     */
    @Override
    public ElectricityWVo getLatestEnergyByClientId(String clientId) {
        log.debug("查询设备{}的最新用电量值", clientId);
        
        LambdaQueryWrapper<ElectricityW> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ElectricityW::getClientId, clientId)
               .orderByDesc(ElectricityW::getCreateTime)
               .last("LIMIT 1");
        
        return electricityWMapper.selectVoOne(wrapper);
    }

    /**
     * 根据设备ID和时间范围查询用电量值列表
     */
    @Override
    public List<ElectricityWVo> getEnergyByClientIdAndTimeRange(String clientId, Date startTime, Date endTime) {
        log.debug("查询设备{}在时间范围[{}, {}]内的用电量值", clientId, startTime, endTime);
        
        LambdaQueryWrapper<ElectricityW> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ElectricityW::getClientId, clientId)
               .ge(startTime != null, ElectricityW::getCreateTime, startTime)
               .le(endTime != null, ElectricityW::getCreateTime, endTime)
               .orderByDesc(ElectricityW::getCreateTime);
        
        return electricityWMapper.selectVoList(wrapper);
    }

    /**
     * 根据设备编号查询能耗统计数据
     */
    @Override
    public List<EnergyStatisticsVo> getEnergyStatistics(String equipmentSn, String energyType, Date startTime, Date endTime) {
        log.debug("查询设备{}的能耗统计数据，能源类型：{}，时间范围：[{}, {}]", equipmentSn, energyType, startTime, endTime);
        
        LambdaQueryWrapper<EnergyStatistics> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(EnergyStatistics::getEquipmentSn, equipmentSn)
               .eq(energyType != null, EnergyStatistics::getEnergyType, energyType)
               .ge(startTime != null, EnergyStatistics::getTime, startTime)
               .le(endTime != null, EnergyStatistics::getTime, endTime)
               .orderByDesc(EnergyStatistics::getTime);
        
        return energyStatisticsMapper.selectVoList(wrapper);
    }

    /**
     * 获取多个设备的最新电力数据汇总
     */
    @Override
    public Map<String, Map<String, Object>> getLatestDataSummary(List<String> clientIds) {
        log.debug("获取设备列表{}的最新电力数据汇总", clientIds);
        
        Map<String, Map<String, Object>> result = new HashMap<>();
        
        for (String clientId : clientIds) {
            Map<String, Object> deviceData = new HashMap<>();
            
            // 获取最新电压值
            ElectricityUVo voltage = getLatestVoltageByClientId(clientId);
            deviceData.put("voltage", voltage);
            
            // 获取最新电流值
            ElectricityIVo current = getLatestCurrentByClientId(clientId);
            deviceData.put("current", current);
            
            // 获取最新功率值
            ElectricityPVo power = getLatestPowerByClientId(clientId);
            deviceData.put("power", power);
            
            // 获取最新用电量值
            ElectricityWVo energy = getLatestEnergyByClientId(clientId);
            deviceData.put("energy", energy);
            
            result.put(clientId, deviceData);
        }
        
        return result;
    }

    /**
     * 根据时间范围获取所有设备的电力数据统计
     */
    @Override
    public Map<String, BigDecimal> getAllDevicesStatistics(Date startTime, Date endTime) {
        log.debug("获取时间范围[{}, {}]内所有设备的电力数据统计", startTime, endTime);
        
        Map<String, BigDecimal> statistics = new HashMap<>();
        
        // 统计总用电量
        LambdaQueryWrapper<ElectricityW> energyWrapper = Wrappers.lambdaQuery();
        energyWrapper.ge(startTime != null, ElectricityW::getCreateTime, startTime)
                    .le(endTime != null, ElectricityW::getCreateTime, endTime);
        
        List<ElectricityWVo> energyList = electricityWMapper.selectVoList(energyWrapper);
        BigDecimal totalEnergy = energyList.stream()
                .map(ElectricityWVo::getValue)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        statistics.put("totalEnergy", totalEnergy);
        
        // 统计平均电压
        LambdaQueryWrapper<ElectricityU> voltageWrapper = Wrappers.lambdaQuery();
        voltageWrapper.ge(startTime != null, ElectricityU::getCreateTime, startTime)
                     .le(endTime != null, ElectricityU::getCreateTime, endTime);
        
        List<ElectricityUVo> voltageList = electricityUMapper.selectVoList(voltageWrapper);
        if (!voltageList.isEmpty()) {
            BigDecimal avgVoltage = voltageList.stream()
                    .map(ElectricityUVo::getValue)
                    .reduce(BigDecimal.ZERO, BigDecimal::add)
                    .divide(BigDecimal.valueOf(voltageList.size()), 2, BigDecimal.ROUND_HALF_UP);
            statistics.put("avgVoltage", avgVoltage);
        }
        
        return statistics;
    }

    /**
     * 获取指定设备的实时数据（最新的电压、电流、功率、用电量）
     */
    @Override
    public Map<String, Object> getRealTimeData(String clientId) {
        log.debug("获取设备{}的实时数据", clientId);
        
        Map<String, Object> realTimeData = new HashMap<>();
        
        // 获取最新数据
        ElectricityUVo voltage = getLatestVoltageByClientId(clientId);
        ElectricityIVo current = getLatestCurrentByClientId(clientId);
        ElectricityPVo power = getLatestPowerByClientId(clientId);
        ElectricityWVo energy = getLatestEnergyByClientId(clientId);
        
        realTimeData.put("clientId", clientId);
        realTimeData.put("voltage", voltage != null ? voltage.getValue() : null);
        realTimeData.put("current", current != null ? current.getValue() : null);
        realTimeData.put("power", power != null ? power.getValue() : null);
        realTimeData.put("energy", energy != null ? energy.getValue() : null);
        
        // 获取最新数据时间
        Date latestTime = null;
        if (voltage != null && voltage.getCreateTime() != null) {
            latestTime = voltage.getCreateTime();
        }
        if (current != null && current.getCreateTime() != null && 
            (latestTime == null || current.getCreateTime().after(latestTime))) {
            latestTime = current.getCreateTime();
        }
        if (power != null && power.getCreateTime() != null && 
            (latestTime == null || power.getCreateTime().after(latestTime))) {
            latestTime = power.getCreateTime();
        }
        if (energy != null && energy.getCreateTime() != null && 
            (latestTime == null || energy.getCreateTime().after(latestTime))) {
            latestTime = energy.getCreateTime();
        }
        
        realTimeData.put("lastUpdateTime", latestTime);
        realTimeData.put("isOnline", isDeviceOnline(clientId, 10)); // 10分钟超时
        
        return realTimeData;
    }

    /**
     * 批量插入电压数据
     * 注意：这里只提供接口框架，具体的批量插入逻辑需要根据实际需求实现
     */
    @Override
    @Transactional
    public int batchInsertVoltageData(List<ElectricityUVo> voltageList) {
        log.debug("批量插入{}条电压数据", voltageList.size());
        
        // TODO: 实现批量插入逻辑
        // 可以使用MyBatis-Plus的saveBatch方法或者自定义SQL
        // 这里提供基本框架，具体实现需要根据业务需求调整
        
        return 0; // 返回实际插入的记录数
    }

    /**
     * 批量插入电流数据
     */
    @Override
    @Transactional
    public int batchInsertCurrentData(List<ElectricityIVo> currentList) {
        log.debug("批量插入{}条电流数据", currentList.size());
        
        // TODO: 实现批量插入逻辑
        
        return 0; // 返回实际插入的记录数
    }

    /**
     * 批量插入功率数据
     */
    @Override
    @Transactional
    public int batchInsertPowerData(List<ElectricityPVo> powerList) {
        log.debug("批量插入{}条功率数据", powerList.size());
        
        // TODO: 实现批量插入逻辑
        
        return 0; // 返回实际插入的记录数
    }

    /**
     * 批量插入用电量数据
     */
    @Override
    @Transactional
    public int batchInsertEnergyData(List<ElectricityWVo> energyList) {
        log.debug("批量插入{}条用电量数据", energyList.size());
        
        // TODO: 实现批量插入逻辑
        
        return 0; // 返回实际插入的记录数
    }

    /**
     * 定时任务：清理过期数据
     */
    @Override
    @Transactional
    public int cleanExpiredData(int daysToKeep) {
        log.info("开始清理{}天前的过期数据", daysToKeep);
        
        Date expireDate = DateUtils.addDays(new Date(), -daysToKeep);
        int totalDeleted = 0;
        
        // 清理电压数据
        LambdaQueryWrapper<ElectricityU> voltageWrapper = Wrappers.lambdaQuery();
        voltageWrapper.lt(ElectricityU::getCreateTime, expireDate);
        int voltageDeleted = electricityUMapper.delete(voltageWrapper);
        totalDeleted += voltageDeleted;
        log.debug("清理电压数据{}条", voltageDeleted);
        
        // 清理电流数据
        LambdaQueryWrapper<ElectricityI> currentWrapper = Wrappers.lambdaQuery();
        currentWrapper.lt(ElectricityI::getCreateTime, expireDate);
        int currentDeleted = electricityIMapper.delete(currentWrapper);
        totalDeleted += currentDeleted;
        log.debug("清理电流数据{}条", currentDeleted);
        
        // 清理功率数据
        LambdaQueryWrapper<ElectricityP> powerWrapper = Wrappers.lambdaQuery();
        powerWrapper.lt(ElectricityP::getCreateTime, expireDate);
        int powerDeleted = electricityPMapper.delete(powerWrapper);
        totalDeleted += powerDeleted;
        log.debug("清理功率数据{}条", powerDeleted);
        
        // 清理用电量数据
        LambdaQueryWrapper<ElectricityW> energyWrapper = Wrappers.lambdaQuery();
        energyWrapper.lt(ElectricityW::getCreateTime, expireDate);
        int energyDeleted = electricityWMapper.delete(energyWrapper);
        totalDeleted += energyDeleted;
        log.debug("清理用电量数据{}条", energyDeleted);
        
        log.info("清理过期数据完成，共清理{}条记录", totalDeleted);
        return totalDeleted;
    }

    /**
     * 获取设备状态（根据最新数据时间判断设备是否在线）
     */
    @Override
    public boolean isDeviceOnline(String clientId, int timeoutMinutes) {
        log.debug("检查设备{}是否在线，超时时间：{}分钟", clientId, timeoutMinutes);
        
        Date timeoutDate = DateUtils.addMinutes(new Date(), -timeoutMinutes);
        
        // 检查各类数据的最新时间
        ElectricityUVo voltage = getLatestVoltageByClientId(clientId);
        ElectricityIVo current = getLatestCurrentByClientId(clientId);
        ElectricityPVo power = getLatestPowerByClientId(clientId);
        ElectricityWVo energy = getLatestEnergyByClientId(clientId);
        
        // 如果任何一种数据的最新时间在超时时间内，则认为设备在线
        boolean isOnline = false;
        
        if (voltage != null && voltage.getCreateTime() != null && voltage.getCreateTime().after(timeoutDate)) {
            isOnline = true;
        }
        if (current != null && current.getCreateTime() != null && current.getCreateTime().after(timeoutDate)) {
            isOnline = true;
        }
        if (power != null && power.getCreateTime() != null && power.getCreateTime().after(timeoutDate)) {
            isOnline = true;
        }
        if (energy != null && energy.getCreateTime() != null && energy.getCreateTime().after(timeoutDate)) {
            isOnline = true;
        }
        
        log.debug("设备{}状态：{}", clientId, isOnline ? "在线" : "离线");
        return isOnline;
    }
}